home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Sound / MIDI / MIDI Utilities / CMU Midi Toolkit / Source / macmidi.c < prev    next >
Text File  |  1988-01-11  |  28KB  |  905 lines

  1. /*
  2.  * macmidi.c -- MIDI interface for the Macintosh
  3.  *
  4.  * this module handles midi initialization, termination, timing, and i/o.
  5.  * because it was originally written for the Roland MPU-401
  6.  * IBM PC interface, some procedures in this module still have
  7.  * the letters"mpu" in them -- history does leave its mark!
  8.  */
  9.  
  10. /*****************************************************************************
  11. *        Change Log
  12. *  Date        | Change
  13. *-----------+-----------------------------------------------------------------
  14. * 31-Dec-85 | Created changelog
  15. * 30-Sep-86 | JMaloney: Converted "mpu.c" to Macintosh
  16. *            |    and renamed to "macmidi.c"
  17. *  7-Oct-86 | JMaloney: Put in abort watcher
  18. *  9-Oct-86 | JMaloney: Allow multiple midi output ports
  19. * 21-Oct-86 | JMaloney: Do MIDI out via Mac serial drivers
  20. * 22-Oct-86 | JMaloney: Moved abort handling to userio.c
  21. *  8-Jan-87 | JMaloney: Converted to Lightspeed C
  22. * 17-Jan-87 | JMaloney: Added synth_init
  23. *****************************************************************************/
  24.  
  25. /* NOTE: the interface between this module and the midi input driver:
  26.  *
  27.  * the midi input driver parses incoming midi data in order to do
  28.  * things like filtering out system exlusive messages.
  29.  * to avoid reparsing at this level, the data is buffered in a
  30.  * queue of messages rather than a simple byte stream.    each message
  31.  * is a 4-byte block.  the first byte is a status byte and the following
  32.  * bytes (one or two) are data bytes. the fourth byte is unused.
  33.  *
  34.  * system exclusive messages are handled by copying the midi exclusive
  35.  * data into a separate buffer provided by the application program
  36.  * through the midi_buffer() call.  the input driver takes care of this.
  37.  */
  38.  
  39. #include "switches.h"
  40.  
  41. #ifdef LIGHTSPEED
  42. #include "Proto.h"
  43. #include <StdIO.h>
  44. #endif
  45.  
  46. #ifdef MPW
  47. #include <StdIO.h>
  48. #endif
  49.  
  50. #include "cext.h"
  51. #include "cmdline.h"
  52. #include "midibuff.h"
  53. #include "midicode.h"
  54. #include "mididriver.h"
  55. #include "mpu.h"
  56. #include "pitch.h"
  57. #include "userio.h"
  58.  
  59. /****************************************************************************
  60. *
  61. *    constants
  62. *
  63. ****************************************************************************/
  64.  
  65. /* define DEBUG to enable extra debugging */
  66. #define DEBUG
  67.  
  68. /* the modem port, also called port A */
  69. #define portA 0
  70.  
  71. /* the printer port, also called port B */
  72. #define portB 1
  73.  
  74. /* port numbers are in the range 0..MAX_PORTS-1 */
  75. #define CHANNELS_PER_PORT 16
  76. #define MAX_PORTS ((MAX_CHANNELS + CHANNELS_PER_PORT - 1) / CHANNELS_PER_PORT)
  77.  
  78. /****************************************************************************
  79. *
  80. *    timer related stuff
  81. *
  82. ****************************************************************************/
  83.  
  84. /* a tick is 1/60 of a second
  85.  *
  86.  * the following tables and routines are used to convert
  87.  * between ticks and hundredths of a second
  88.  * the maximum error going from ticks to hundredths is 2/500ths of a second
  89.  * the maximum error going from hundredths to ticks is 1/300th of a second
  90.  */
  91.  
  92. /* conversion tables */
  93. private ulong toHundredths[] = {0, 2, 3};
  94. private ulong toTicks[] = {0, 1, 1, 2, 2};
  95.  
  96. #define TICKS_TO_HUNDREDTHS(t)  ((((t) / 3L) * 5L) + toHundredths[(t) % 3L])
  97. #define HUNDREDTHS_TO_TICKS(t)  ((((t) / 5L) * 3L) + toTicks[(t) % 5L])
  98.  
  99. /****************************************************************************
  100. *
  101. *    variables shared with other modules
  102. *
  103. ****************************************************************************/
  104.  
  105. boolean do_midi_thru = false;
  106.                         /* exported: copy midi in to midi out */
  107. boolean miditrace = false;
  108.                         /* exported: enables printed trace of MIDI output */
  109. boolean musictrace = false;
  110.                         /* exported: enables printed trace of commands */
  111. boolean ctrlFilter = true;
  112.                         /* exported: suppress continuous controller data */
  113.  
  114. int num_channels = 16;    /* exported: should be controlled by the user,
  115.                          *    depending on the number of midi output devices
  116.                          *    (you get 16 channels per device), but I haven't
  117.                          *    decided out how to do it yet!
  118.                          */
  119.  
  120. /****************************************************************************
  121. *
  122. *    midi input and system exclusive buffers
  123. *        NOTE: these buffers are SHARED with the midi input driver
  124. *
  125. ****************************************************************************/
  126.  
  127. /* midi input buffer */
  128. byte buff[BUFF_SIZE];    /* data buffer */
  129. int buffhead = 0;        /* buffer head and tail pointers */
  130. int bufftail = 0;
  131.  
  132. /* user supplied system exclusive buffer */
  133. byte *xbuff = NULL;        /* address of the user-supplied buffer */
  134. int xbuffmask;            /* mask for circular buffer address calculation */
  135. int xbuffhead = 0;        /* buffer head and tail pointers */
  136. int xbufftail = 0;
  137.  
  138. /****************************************************************************
  139. *
  140. *    variables private to this module
  141. *
  142. ****************************************************************************/
  143.  
  144. private boolean initialized = false;
  145.     /* set by musicinit, cleared by musicterm
  146.      * indicates the current state of the midi drivers */
  147.  
  148. private boolean simulate = false;
  149.     /* used for debugging
  150.      * if simulate is true, no midi output is actually performed */
  151.  
  152. private boolean user_retuning_on = false;
  153.     /* true if the user defined his own scale
  154.      * set by read_tuning, never cleared */
  155.  
  156. private short bend[MAX_CHANNELS];
  157.     /* current pitch bend on each channel
  158.      * used to avoid sending extra pitch bend commands
  159.      * NOTE: voice 1's bend is in bend[0] */
  160.  
  161. private short midi_prog[MAX_CHANNELS];
  162.     /* current program ("preset" or "instrument") for each channel
  163.      * used to avoid sending extra program change commands
  164.      * NOTE: voice 1's program is in program[0] */
  165.  
  166. private pitch_table pitch_tab[128];
  167.     /* user's scale definition
  168.      * initialize by read_tuning if the user specifies "-tune" option
  169.      * NOTE: not initialized or used otherwise */
  170.  
  171. private ulong ticksAtStart = 0;
  172.     /* clock ticks at time of last musicinit or timereset
  173.      * ASSUME: tick clock never wraps.  this is a good assumption, since
  174.      * the tick clock is set to zero when the power is turned on and the
  175.      * tick counter is 32 bits.  the Macintosh would need to be on for
  176.      * 828.5 days for the tick counter to wrap around! */
  177.  
  178. /****************************************************************************
  179. *
  180. *    routines private to this module
  181. *
  182. ****************************************************************************/
  183.  
  184. void    fixup(void);
  185. void    map_channel(int, int *, int *);
  186. void    putbyte(int, byte);
  187.  
  188. /****************************************************************************
  189. *                    exclusive
  190. * Inputs:
  191. *    boolean onflag: set to true to receive midi exclusive data
  192. * Effect:
  193. *    tells midi i/o device to accept exclusive messages into buffer
  194. *    (this is a noop on the Macintosh; it is kept for compatability)
  195. ****************************************************************************/
  196.  
  197. public void exclusive(onflag)
  198.     boolean onflag;
  199. {
  200.     if (!initialized) fixup();
  201.     if (musictrace) gprintf(TRANS, "exclusive: %s\n", (onflag ? "on" : "off"));
  202. }
  203.  
  204. /****************************************************************************
  205. *                    fixup
  206. * Effect:
  207. *    print error message and call musicinit
  208. ****************************************************************************/
  209.  
  210. private void fixup()
  211. {
  212.     gprintf(ERROR, "You forgot to call musicinit. I'll do it for you.\n");
  213.     musicinit();
  214. }
  215.  
  216. /****************************************************************************
  217. *                    getbuf
  218. * Inputs:
  219. *    boolean waitflag: true if routine should wait for data
  220. *    byte * p: pointer to 4 byte data destination
  221. * Returns:
  222. *    boolean: true if data was written to *p false otherwise
  223. * Effect:
  224. *    copies data from buffer to *p
  225. *    will wait for buffer to become nonempty if waitflag is true
  226. ****************************************************************************/
  227.  
  228. public boolean getbuf(waitflag, p)
  229.    boolean waitflag;
  230.    byte *p;
  231. {
  232.     if (!initialized) return false;
  233.     if (waitflag) {
  234.         while (buffhead == bufftail) /* wait */;
  235.     } else {
  236.         if (buffhead == bufftail) return false;
  237.     }
  238.  
  239.     *(ulong *) p = *(ulong *) (buff + buffhead);
  240.     buffhead = (buffhead + 4) & BUFF_MASK;
  241.  
  242. /* the previous two lines are an optimization of:
  243.  *
  244.  *    *p++ = buff[buffhead++];
  245.  *    *p++ = buff[buffhead++];
  246.  *    *p++ = buff[buffhead++];
  247.  *    buffhead++;
  248.  *
  249.  *    if (buffhead >= BUFF_SIZE) buffhead = 0;
  250.  */
  251.     return true;
  252. }
  253.  
  254. /****************************************************************************
  255. *                    getkey
  256. * Inputs:
  257. *    boolean waitflag: if true wait until key depression else return immediately
  258. * Returns:
  259. *    int: key number of the key which has been depressed, or
  260. *         -1 if waitflag is false and no key has been depressed
  261. *    int * velocity: set to the velocity of the key depressed, if there is one
  262. * Effect:
  263. *    reads midi input buffer until it finds a key up or down event
  264. *    throws away all buffered midi events up until the key event
  265. *    if waitflag is true this routine will block until a key is depressed
  266. ****************************************************************************/
  267.  
  268. public int getkey(waitflag, velocity)
  269.     boolean waitflag;
  270.     int *velocity;
  271. {
  272.     byte msg[4];
  273.     int key;
  274.  
  275.     if (!initialized) return -1;
  276.     *velocity = 0;
  277.     while (true) {    /* process data until you find a note */
  278.         /* look for data and exit if none found */
  279.         /* NOTE: waitflag will force getbuf to wait until data arrives */
  280.         if (!getbuf(waitflag, msg)) {        /* nothing there */
  281.             key = -1;
  282.             break;
  283.         } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) {
  284.             if (msg[2] == 0) {                /* velocity 0 implies note off */
  285.                 *velocity = 0;
  286.                 key = (msg[1] - 12) + 128;    /* add 128 to show note off */
  287.             } else {
  288.                 *velocity = msg[2];            /* note on */
  289.                 key = (msg[1] - 12);
  290.             }
  291.             break;
  292.         } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) {
  293.             *velocity = 0;
  294.             key = (msg[1] - 12) + 128;        /* add 128 to show note off */
  295.             break;
  296.         }
  297.     }
  298.  
  299.     if (musictrace) {
  300.         if (key != -1)
  301.             gprintf(TRANS,
  302.                 "getkey got %d (velocity: %d)\n", key, *velocity);
  303.     }
  304.     return key;
  305. }
  306.  
  307. /****************************************************************************
  308. *                    gettime
  309. * Returns:
  310. *    ulong: the time in 100ths of seconds since the last timereset
  311. ****************************************************************************/
  312.  
  313. public ulong gettime()
  314. {
  315.     register ulong ticks = TickCount() - ticksAtStart;
  316.  
  317.     if (initialized) abort_check();    /* give user a chance to abort */
  318.     return TICKS_TO_HUNDREDTHS(ticks);
  319. }
  320.  
  321. /****************************************************************************
  322. *                    l_rest
  323. * Inputs:
  324. *    ulong dur: amount of time to rest, in 100ths of a second
  325. * Effect:
  326. *    waits until the amount of time specified has lapsed
  327. ****************************************************************************/
  328.  
  329. public void l_rest(dur)
  330.     ulong dur;
  331. {
  332.     l_restuntil(gettime() + dur);
  333. }
  334.  
  335. /****************************************************************************
  336. *                    l_restuntil
  337. * Inputs:
  338. *    ulong absTime: absolute time to rest until, in 100ths of a second
  339. * Effect:
  340. *    waits until the specified time has been reached (absolute time
  341. *    is in 100ths of seconds since the last timereset call)
  342. ****************************************************************************/
  343.  
  344. public void l_restuntil(absTime)
  345.     ulong absTime;
  346. {
  347.     ulong now = gettime();
  348.     ulong junk;
  349.  
  350.     if (absTime > now)  Delay(HUNDREDTHS_TO_TICKS(absTime - now), &junk);
  351.     /* else time <= now, so return immediately */
  352. }
  353.  
  354. /****************************************************************************
  355. *                    map_channel
  356. * Inputs:
  357. *    int voice: voice number (or "abstract channel number")
  358. * Returns:
  359. *    int * port: set to the midi output port on which to send midi data
  360. *    int * channel: set to channel number to be used in the midi command
  361. * Effect:
  362. *    maps a voice number onto a (port, channel) pair
  363. *    NOTE: do not confuse a "voice" number with a "channel" number
  364. *    voice numbers start with 1 whereas channel numbers start with 0.
  365. * Implementation:
  366. *    there may be several different hardware ports for midi output. ports
  367. *    are numbered 0,1,2, etc. there are sixteen midi channels per
  368. *    port, numbered 0 through 15. the global variable "num_channels"
  369. *    should be initialized to (16 * <number of ports>). right now, there is no
  370. *    way to intialize it except by re-compiling; ideally, it would be
  371. *    a command-line option.
  372. ****************************************************************************/
  373.  
  374. private void map_channel(voice, port, channel)
  375.     int voice;
  376.     int *port;
  377.     int *channel;
  378. {
  379. #ifdef DEBUG
  380.     if ((voice < 1) || (voice > num_channels)) {
  381.         gprintf(ERROR,
  382.             "Implementation error (macmidi.c): invalid voice number %d\n",
  383.             voice);
  384.         *port = 0;    /* if error, default to channel 0, port 0 and go on */
  385.         *channel = 0;
  386.         return;
  387.     }
  388. #endif
  389.  
  390.     *port = (voice -1) >> 4;        /* divide by 16; port is the high bits */
  391.     *channel = (voice - 1) & 0x0F;    /* channel is low 4 bits */
  392. }
  393.  
  394. /****************************************************************************
  395. *                    metronome
  396. * Inputs:
  397. *    int onflag: true or false
  398. * Effect:
  399. *    enables (true) or disables (false) the midi hardware metronome function
  400. *    must be called before musicinit for MPU-401
  401. *    this may be a noop if there is no metronome in the midi hardware
  402. *    (as is the case on the Macintosh)
  403. ****************************************************************************/
  404.  
  405. public void metronome(onflag)
  406.     int onflag;
  407. {
  408.     /* not supported on the Macintosh */
  409. }
  410.  
  411. /****************************************************************************
  412. *                    midi_bend
  413. * Inputs:
  414. *    int voice: midi voice on which to send data
  415. *    int value: pitch bend value
  416. * Effect:
  417. *    sends a midi pitch bend message
  418. ****************************************************************************/
  419.  
  420. public void midi_bend(voice, value)
  421.     int voice;
  422.     int value;
  423. {
  424.     int port, midi_chan;
  425.  
  426.     if (!initialized) fixup();
  427.     if (bend[voice - 1] == value) return;    /* noop if bend already bent */
  428.     if (musictrace)
  429.         gprintf(TRANS, "midi_bend: ch %d, val %d\n", voice, value);
  430.     bend[voice - 1] = value;    /* remember current bend */
  431.     map_channel(voice, &port, &midi_chan);
  432.     putbyte(port, MIDI_BEND | midi_chan);
  433.     putbyte(port, MIDI_DATA(value));
  434.     putbyte(port, MIDI_DATA(value >> 7));
  435.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  436. }
  437.  
  438. /****************************************************************************
  439. *                    midi_buffer
  440. * Inputs:
  441. *    byte * buffer: the buffer address
  442. *    int size: number of bytes in buffer
  443. * Returns:
  444. *    boolean: false if size is less than 16 or buffer is NULL, otherwise true
  445. * Effect:
  446. *    tells interrupt routine to store system exclusive messages in buffer.
  447. *    the largest power of 2 bytes less than size will be used.
  448. *    xbuffhead and xbufftail will be initialized to zero,
  449. *    and xbufftail will be one greater than the index of the last
  450. *    system exclusive byte read from mpu401.
  451. ****************************************************************************/
  452.  
  453. public boolean midi_buffer(buffer, size)
  454.     byte *buffer;
  455.     int size;
  456. {
  457.     int mask;
  458.  
  459.     mask = 16 - 1;
  460.     if ((size < 16) || (buffer == NULL)) return false;
  461.     while ((mask < size) && (mask > 0))
  462.         mask = (mask << 1) + 1;
  463.     xbuff = NULL;    /* turn off buffering */
  464.     xbuffmask = mask >> 1;
  465.     xbuffhead = xbufftail = 0;
  466.     xbuff = buffer;    /* set buffer; this turns on buffering */
  467.     return true;
  468. }
  469.  
  470. /****************************************************************************
  471. *                    midi_cont
  472. * Inputs:
  473. *    boolean onflag: true allows continuous controller data to pass through
  474. * Effect:
  475. *    continuous controller data from the midi controller (e.g. pitch bends)
  476. *    are normally filtered out.  midi_cont allows one to accept this data.
  477. * NOTE:
  478. *    if continuous controller data is accepted one must read and empty the
  479. *    input buffer more frequently to avoid data overruns.
  480. ****************************************************************************/
  481.  
  482. public void midi_cont(onflag)
  483.     boolean onflag;
  484. {
  485.     ctrlFilter = !onflag;
  486. }
  487.  
  488. /****************************************************************************
  489. *                    midi_ctrl
  490. * Inputs:
  491. *    int voice: midi voice on which to send data
  492. *    int control: control number
  493. *    int value: control value
  494. * Effect:
  495. *    sends a midi control change message
  496. ****************************************************************************/
  497.  
  498. public void midi_ctrl(voice, control, value)
  499.     int voice;
  500.     int control;
  501.     int value;
  502. {
  503.     int port, midi_chan;
  504.  
  505.     if (!initialized) fixup();
  506.     if (musictrace)
  507.         gprintf(TRANS, "midi_ctrl: ch %d, ctrl %d, val %d\n",
  508.                 voice, control, value);
  509.     map_channel(voice, &port, &midi_chan);
  510.     putbyte(port, MIDI_CTRL | midi_chan);
  511.     putbyte(port, MIDI_DATA(control));
  512.     putbyte(port, MIDI_DATA(value));
  513.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  514. }
  515.  
  516. /****************************************************************************
  517. *                    midi_exclusive
  518. * Inputs:
  519. *    int port: port number to send on
  520. *    byte * msg: pointer to a midi exclusive message, terminated by 0xF7
  521. * Effect:
  522. *    sends a midi exclusive message
  523. ****************************************************************************/
  524.  
  525. #define INTERBYTE_DELAY 10
  526.  
  527. public void midi_exclusive(port, msg)
  528.     int port;
  529.     byte *msg;
  530. {
  531.     int i;            /* for DX7 delay loop */
  532.     int count = 0;    /* counter for formatting midi byte trace */
  533.  
  534.     /* if user mistakenly called midi_exclusive instead of exclusive,
  535.      * the argument will be true or false, both of which are highly
  536.      * unlikely valid arguments for midi_exclusive:
  537.      */
  538.     if ((msg == (byte *) false) || (msg == (byte *) true)) {
  539.         gprintf(FATAL, "midi_exclusive: invalid argument %d.", (int) msg);
  540.         clean_exit();
  541.     }
  542.  
  543.     if (!initialized) fixup();
  544.     if (musictrace) gprintf(TRANS, "midi_exclusive\n");
  545.     if (miditrace) gprintf(TRANS, "\n");
  546.     while (*msg != MIDI_EOX) {
  547.         putbyte(port, *msg);
  548.         msg++;
  549.         count++;
  550.         if (miditrace && ((count % 16) == 0)) {
  551.             gprintf(TRANS, "[%d]\n", port);
  552.         }
  553.         /* this is a delay loop, without which your DX7 will crash */
  554.         for (i = INTERBYTE_DELAY; i > 0; i--)
  555.             abort_check();
  556.     }
  557.     putbyte(port, MIDI_EOX);
  558.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  559. }
  560.  
  561. /****************************************************************************
  562. *                    midi_note
  563. * Inputs:
  564. *    int voice: midi voice on which to send data
  565. *    int pitch: midi pitch code
  566. *    int velocity: velocity with which to sound it (0=> release)
  567. * Effect:
  568. *    sends a midi note-on message
  569. ****************************************************************************/
  570.  
  571. public void midi_note(voice, pitch, velocity)
  572.     int voice;
  573.     int pitch;
  574.     int velocity;
  575. {
  576.     int port, midi_chan;
  577.  
  578.     if (!initialized) fixup();
  579.     if (musictrace)
  580.         gprintf(TRANS, "midi_note: ch %d, key %d, vel %d\n",
  581.                 voice, pitch, velocity);
  582.     if (user_retuning_on) {
  583.         /* set correct pitch bend if necessary */
  584.         if (velocity != 0) midi_bend(voice, pitch_tab[pitch+12].pbend);
  585.         pitch = pitch_tab[pitch+12].ppitch;
  586.     }
  587.  
  588.     map_channel(voice, &port, &midi_chan);
  589.     putbyte(port, MIDI_ON_NOTE | midi_chan);
  590.     putbyte(port, MIDI_DATA(12 + pitch));    /* cmu to midi standard pitch */
  591.     putbyte(port, MIDI_DATA(velocity));
  592.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  593. }
  594.  
  595. /****************************************************************************
  596. *                    midi_program
  597. * Inputs:
  598. *    int voice: midi voice on which to send midi program change message
  599. *    int prog: program number to send (decremented by 1 before
  600. *              being sent as midi data)
  601. * Effect:
  602. *    sends a program change message
  603. ****************************************************************************/
  604.  
  605. public void midi_program(voice, prog)
  606.     int voice;
  607.     int prog;
  608. {
  609.     int port, midi_chan;
  610.  
  611.     if (!initialized) fixup();
  612.     if (prog == midi_prog[voice - 1]) return; /* noop if program already set */
  613.     if (musictrace)
  614.         gprintf(TRANS, "midi_program: ch %d, prog %d\n", voice, prog);
  615.     midi_prog[voice - 1] = prog;              /* remember new setting */
  616.     map_channel(voice, &port, &midi_chan);
  617.     putbyte(port, MIDI_CH_PROGRAM | midi_chan);
  618.     putbyte(port, MIDI_PROGRAM(prog));
  619.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  620. }
  621.  
  622. /****************************************************************************
  623. *                    midi_thru
  624. * Inputs:
  625. *    boolean onflag: if true, enable midi thru mode
  626. * Effect:
  627. *    in midi-thru mode, the midi input stream is copied to midi out
  628. *    (the default is enabled; disable with cmdline -block)
  629. ****************************************************************************/
  630.  
  631. public void midi_thru(onflag)
  632.     boolean onflag;
  633. {
  634.     do_midi_thru = onflag;
  635.     /* NOTE: midi thru is not supported on the Macintosh */
  636. }
  637.  
  638. /****************************************************************************
  639. *                    midi_touch
  640. * Inputs:
  641. *    int voice: midi voice on which to send data
  642. *    int value: control value
  643. * Effect:
  644. *    sends a midi after touch message
  645. ****************************************************************************/
  646.  
  647. public void midi_touch(voice, value)
  648.     int voice;
  649.     int value;
  650. {
  651.     int port, midi_chan;
  652.  
  653.     if (!initialized) fixup();
  654.     if (musictrace)
  655.         gprintf(TRANS, "midi_touch: ch %d, val %d\n", voice, value);
  656.     map_channel(voice, &port, &midi_chan);
  657.     putbyte(port, MIDI_TOUCH | midi_chan);
  658.     putbyte(port, MIDI_DATA(value));
  659.     if (miditrace) gprintf(TRANS, "[%d]\n", port);
  660. }
  661.  
  662. /****************************************************************************
  663. *                    mpuexists
  664. * Inputs:
  665. *    boolean flag: false to simulate midi hardware
  666. * Effect:
  667. *    if argument is false, indicates no midi hardware is on the machine
  668. *    (this feature is useful for debugging)
  669. ****************************************************************************/
  670.  
  671. public void mpuexists(flag)
  672.     boolean flag;
  673. {
  674.     simulate = !flag;
  675. }
  676.  
  677. /****************************************************************************
  678. *                    musicinit
  679. * Effect:
  680. *    check for miditrace and musictrace switches
  681. *    read tuning file if necessary (this is done at most once)
  682. *    initialize the midi device drivers
  683. *    initialize bend and program arrays (first time)
  684. *    reset the clock
  685. ****************************************************************************/
  686.  
  687. public void musicinit()
  688. {
  689.     static boolean first_time = true;
  690.         /* set to false by first call to musicinit
  691.          * used to avoid command-line processing, re-tuning more than once */
  692.     int i;
  693.  
  694. #ifndef APPLICATION
  695.     if (first_time) {    /* do this code only once */
  696.         /* process command-line switches, including "-tune" */
  697.         char *tuneFile = cl_option("-tune");
  698.  
  699.         musictrace = (cl_switch("-trace") || cl_switch("-t"));
  700.         miditrace = (cl_switch("-miditrace") || cl_switch("-m"));
  701.         do_midi_thru = !(cl_switch("-block"));
  702.         if (tuneFile != NULL) {
  703.             read_tuning(tuneFile);
  704.             user_retuning_on = true;
  705.         }
  706.     }
  707. #endif
  708.  
  709.     if (!initialized) {
  710.         initialized = true;    /* must do early to avoid recursive loop! */
  711.         init_abort_handler();
  712.         setupMIDI(portA, 0x80);
  713.         if (num_channels > CHANNELS_PER_PORT) setupMIDI(portB, 0x80);
  714.             /* only initialize portB if necessary */
  715.         ticksAtStart = TickCount();    /* reset the clock */
  716.     }
  717.  
  718.     if (first_time) {    /* do this code only once */
  719.         first_time = false;
  720.         for (i = 0; i < MAX_CHANNELS; i++) {
  721.             bend[i] = -1;        /* impossible value; fixed by synth_init */
  722.             midi_prog[i] = -1;    /* impossible value; fixed by synth_init */
  723.         }
  724.         synth_init();    /* set initial synth state */
  725.     }
  726. }
  727.  
  728. /****************************************************************************
  729. *                    musicterm
  730. * Effect:
  731. *    cleans up: turns off all voices, turns off interrupts
  732. ****************************************************************************/
  733.  
  734. #define ALL_NOTES_OFF 123
  735.  
  736. public void musicterm()
  737. {
  738.     int i;
  739.  
  740.     if (initialized) {
  741.         for (i = 1; i <= num_channels; i++) {
  742.             /* turns off all notes on all channels */
  743.             midi_ctrl(i, ALL_NOTES_OFF, 0);
  744.         }
  745.  
  746.         /* turn off interrupts, abort watcher */
  747.         restoreMIDI(portA);
  748.         if (num_channels > CHANNELS_PER_PORT) restoreMIDI(portB);
  749.         cleanup_abort_handler();
  750.         initialized = false;
  751.     }
  752. }
  753.  
  754. /****************************************************************************
  755. *                    putbyte
  756. * Inputs:
  757. *    int port: port to send on
  758. *    byte c: character to write
  759. * Effect:
  760. *    writes c to the midi port if simulate is false
  761. ****************************************************************************/
  762.  
  763. private void putbyte(port, c)
  764.     int port;
  765.     byte c;
  766. {
  767.     if (miditrace) gprintf(TRANS, "%3d ", c);
  768.     if (!simulate) Xmit(port, c);
  769. }
  770.  
  771. /****************************************************************************
  772. *                    random
  773. * Inputs:
  774. *    int lo: lower limit of value
  775. *    int hi: upper limit of value
  776. * Returns:
  777. *    int: random number (lo <= result <= hi)
  778. ****************************************************************************/
  779.  
  780. private ulong seed = 1534781;
  781.  
  782. public int random(lo, hi)
  783.     int lo, hi;
  784. {
  785.     seed *= 13;
  786.     seed += 1874351;
  787.     return (int) ((long) lo +
  788.         ((((long) hi + 1 - lo) * ((0x00FFFF00L & seed) >> 8)) >> 16));
  789. }
  790.  
  791. /****************************************************************************
  792. *                    read_tuning
  793. * Inputs:
  794. *    char * filename: name of tuning file
  795. * Effect:
  796. *    initializes re-tuning table with pitches and bends from .tun file
  797. ****************************************************************************/
  798.  
  799. public void read_tuning(filename)
  800.     char *filename;
  801. {
  802.     int index, pit, lineno, i = 0;
  803.     float bend;
  804.     FILE *fp;
  805.  
  806.     /* set up the default pitch table */
  807.     for (i = 0; i < 128; i++) {
  808.         pitch_tab[i].pbend = 8192;
  809.         pitch_tab[i].ppitch = i;
  810.     }
  811.     fp = fileopen(filename, "tun", "r", "Tuning definition file");
  812.     while ((fscanf(fp, "%d %d %f\n", &index, &pit, &bend) == 3) &&
  813.            (lineno < 128)) {
  814.         lineno++;
  815.         if (index >= -12 && index <= 115) {
  816.             pitch_tab[index+12].pbend = (int)(8192 * bend/100 + 8192);
  817.             pitch_tab[index+12].ppitch = pit;
  818.         }
  819.     }
  820. }
  821.  
  822. /****************************************************************************
  823. *                    settime
  824. * Inputs:
  825. *    ulong absTime: time to set
  826. * Effect:
  827. *    sets the clock to absTime
  828. * Implementation:
  829. *    ticksAtStart is adjusted
  830. ****************************************************************************/
  831.  
  832. public void settime(absTime)
  833.     ulong absTime;
  834. {
  835.     if (musictrace) gprintf(TRANS, "settime(%lu)\n", absTime);
  836.     ticksAtStart = TickCount() - HUNDREDTHS_TO_TICKS(absTime);
  837. }
  838.  
  839. /****************************************************************************
  840. *                    synth_init
  841. * Effect:
  842. *    initialize all midi channels with reasonable start values
  843. * NOTE:
  844. *    if "initialized" is not true at this point, you will get into
  845. *    a recursive loop when midi_bend and midi_program call fixup()
  846. ****************************************************************************/
  847.  
  848. void synth_init()
  849. {
  850.     int i;
  851.  
  852.     for (i = 1; i <= num_channels; i++) {
  853.         midi_bend(i, 8192);    /* no bend */
  854.         midi_program(i, 1);    /* default program = 1 */
  855.         midi_touch(i, 0);
  856.         midi_ctrl(i, PORTARATE, 99);
  857.         midi_ctrl(i, PORTASWITCH, 0);    /* off */
  858.         midi_ctrl(i, MODWHEEL, 0);        /* no modulation */
  859.         midi_ctrl(i, FOOT, 99);
  860.         abort_check();    /* give user a chance to abort from this loop */
  861.     }
  862. }
  863.  
  864. /****************************************************************************
  865. *                    timereset
  866. * Effect:
  867. *    resets the clock
  868. * Implementation:
  869. *    ticksAtStart is set to current value of system tick counter
  870. ****************************************************************************/
  871.  
  872. public void timereset()
  873. {
  874.     if (musictrace) gprintf(TRANS, "timereset\n");
  875.     ticksAtStart = TickCount();
  876. }
  877.  
  878. /****************************************************************************
  879. *                    trace
  880. * Inputs:
  881. *    boolean flag: true for trace on
  882. * Effect:
  883. *    turns tracing on or off
  884. ****************************************************************************/
  885.  
  886. public void trace(flag)
  887.     boolean flag;
  888. {
  889.     musictrace = flag;
  890. }
  891.  
  892. /****************************************************************************
  893. *                    tracemidi
  894. * Inputs:
  895. *    boolean flag: true for trace on
  896. * Effect:
  897. *    turns midi tracing on or off
  898. ****************************************************************************/
  899.  
  900. public void tracemidi(flag)
  901.     boolean flag;
  902. {
  903.     miditrace = flag;
  904. }
  905.